/*
 * test_encoder.cpp
 *
 *  Created on: Dec 3, 2016
 *      Author: lwang
 */

#include <codec_manager.h>
#include <vector>
#include <numeric>

#include "tick_meter.hpp"
#include "buffer.h"

using namespace std;
using namespace cv;

int main() {

	VideoCapture capture("/home/nfs/videos/grass1080.mp4");
	if(!capture.isOpened()) {
		cout << "Failed to open capture" << endl;
		return 1;
	}

	Mat frame;
	if(!capture.read(frame)){
		cout << "Failed to read a frame" << endl;
		return 1;
	}

	const string encoder_queue_id = "encQueue";
	const string encoder_buffer_queue_id = "encBufQueue";
	BufferQueue *enc_queue = new BufferQueue(128*1024*1024-1, encoder_queue_id);
	enc_queue->initQueue();

	const string encoder_id = "testEncoder";
	const string decoder_id = "testDecoder";
	const CODEC_TYPE codec_type = CODEC_TYPE_H264_CPU;

	int frame_width = frame.cols;
	int frame_height = frame.rows;

	CodecManager *codec_manager = new CodecManager();
	int register_result = codec_manager->registerEnocder(encoder_id, codec_type,
			frame_width, frame_height);
	if(register_result != CODEC_OK) {
		cout << "Register Encoder Error" << endl;
		return 1;
	}

	register_result = codec_manager->registerDeocder(decoder_id, codec_type);
	if(register_result != CODEC_OK) {
		cout << "Register Decoder Error" << endl;
		return 1;
	}

	unsigned char* buffer = new unsigned char[frame_width * frame_height * frame.channels()];
	int encoded_size = 0;

	Mat yuv_mat;
	std::vector<double> enc_times;
	std::vector<double> dec_times;
	TickMeter tm;

	while(capture.read(frame)) {

		cvtColor(frame, yuv_mat, COLOR_BGR2YUV_I420);
//		cout << "Raw data size : " << yuv_mat.dataend - yuv_mat.datastart << endl;

		BaseEncoder* encoder = codec_manager->getEncoderById(encoder_id);

		tm.reset(); tm.start();
		int codec_error = encoder->encodeFrame(yuv_mat.data, buffer, encoded_size);
        tm.stop();
        enc_times.push_back(tm.getTimeMilli());

		if(codec_error != CODEC_OK) {
			cout << "Encode Error" << endl;
//			goto end;
		}
		enc_queue->enQueue(buffer, encoded_size);
//		cout << "Enqueue buffer with size : " << encoded_size << endl;
	}

	int total_encoded_size = 0;
	enc_queue->queueLength(total_encoded_size);
	int used_data_length = 0;
	Mat dec_frame(yuv_mat);
//	Mat dec_frame_rgb;
	cout << "yuv frame type/channel : " << dec_frame.type()
			<< "/" << dec_frame.channels() << endl;
	while(total_encoded_size > 0) {

		int gotFrame = 0;
//		enc_queue->deQueue(enc_queue->getData(), 2048 - used_data_length);

		BaseDecoder *decoder = codec_manager->getDecoderById(decoder_id);

		tm.reset(); tm.start();
		decoder->decodeFrame(dec_frame, gotFrame, enc_queue->getData(), 4096, used_data_length);
        tm.stop();
        dec_times.push_back(tm.getTimeMilli());

//		cout << "used data size : " << used_data_length << endl;
		total_encoded_size -= used_data_length;
		enc_queue->rewind(used_data_length);

//		if(gotFrame) {
//			cvtColor(dec_frame, dec_frame_rgb, COLOR_YUV2BGR_I420);
//			imshow("decoded_frame", dec_frame_rgb);
//			waitKey(1);
//		}
	}

	std::sort(enc_times.begin(), enc_times.end());
    std::sort(dec_times.begin(), dec_times.end());

    double enc_avg = std::accumulate(enc_times.begin(), enc_times.end(), 0.0) / enc_times.size();
    double dec_avg = std::accumulate(dec_times.begin(), dec_times.end(), 0.0) / dec_times.size();

    std::cout << "ENC : Avg : " << enc_avg << " ms FPS : " << 1000.0 / enc_avg << std::endl;
    std::cout << "DEC : Avg : " << dec_avg << " ms FPS : " << 1000.0 / dec_avg << std::endl;

	codec_manager->releaseEncoder(encoder_id);
	codec_manager->releaseDecoder(decoder_id);
	free(buffer);
	capture.release();
	return 0;
}
